﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Collections;

namespace TinyERP.Framework
{
    internal class ShortcutCommand
    {
        /// <summary>
        /// A string to represent for a combine key. 
        /// Value can be combined by +,-,_, or space
        /// </summary>
        public string ShortCutCombineKey { get; set; }
        /// <summary>
        /// Object to handle this shortcut key
        /// </summary>
        public object Handler { get; set; }
        /// <summary>
        /// Method of the handler object to handle this shortcut. The method must be a public non-param method.
        /// </summary>
        public string HandlingMethod { get; set; }
        public ShortcutCommand(string combineKey, object handler, string handlingMethod)
        {
            this.Handler = handler;
            this.HandlingMethod = handlingMethod;
            this.ShortCutCombineKey = combineKey;
        }
        private bool IsControlKey(string key)
        {
            string keyLower = key.ToLower();
            return keyLower == "ctrl" || keyLower == "shift" || keyLower == "alt";
        }

        private string StandardizeCombinedKeys(string combinedKeys)
        {
            string standardizeCombineKey = combinedKeys;
            standardizeCombineKey = standardizeCombineKey.Replace(' ', '+');
            standardizeCombineKey = standardizeCombineKey.Replace('-', '+');
            standardizeCombineKey = standardizeCombineKey.Replace('_', '+');
            return standardizeCombineKey;
        }

        public bool IsHandlerForEvent(KeyEventArgs ev)
        {
            string standardizedCombineKey = StandardizeCombinedKeys(ShortCutCombineKey);
            string[] partsOfCommand = standardizedCombineKey.Split('+');
            foreach (string key in partsOfCommand)
            {
                if (!IsMatchKey(key, ev))
                {
                    return false;
                }
            }
            return true;
        }

        private bool IsMatchKey(string key, KeyEventArgs ev)
        {
            bool matchControlKey = IsControlKey(key) && IsMatchControlKey(key);
            bool matchNormalKey = !matchControlKey && IsMatchNormalKey(key, ev);
            return matchControlKey || matchNormalKey;
        }

        private bool IsMatchNormalKey(string commandKey, KeyEventArgs ev)
        {
            KeysObject currentKey = KeyLookupTable.GetInstance().GetKeyFromString(commandKey.ToLower());
            return (currentKey!=null && currentKey.Value != Keys.None && currentKey.Value == ev.KeyCode);
        }

        private bool IsMatchControlKey(string controlKey)
        {
            if (controlKey.ToLower() == "ctrl")
            {
                return Control.ModifierKeys == Keys.Control;
            }
            else if (controlKey.ToLower() == "shift")
            {
                return Control.ModifierKeys == Keys.Shift;
            }
            else if (controlKey.ToLower() == "alt")
            {
                return Control.ModifierKeys == Keys.Alt;
            }
            return false;
        }
        public void Execute()
        {
            MethodInfo methodInfo = Handler.GetType().GetMethod(HandlingMethod);
            methodInfo.Invoke(Handler, null);
        }
    }
    public class KeysObject
    {
        public Keys Value { get; set; }
        public KeysObject(Keys keys)
        {
            this.Value = keys;
        }
    }
    public class KeyLookupTable
    {
        private IDictionary<string, KeysObject> keyDictionary;
        private static KeyLookupTable instance;
        private KeyLookupTable()
        {
            keyDictionary = new Dictionary<string, KeysObject>();
            FieldInfo[] fieldInfos = typeof(Keys).GetFields(BindingFlags.Public | BindingFlags.Static);
            foreach (FieldInfo field in fieldInfos)
            {
                keyDictionary[field.Name.ToLower()] = new KeysObject((Keys)field.GetRawConstantValue()); 
            }
        }
        public KeysObject GetKeyFromString(string key)
        {
            if (!keyDictionary.ContainsKey(key))
            {
                return null;
            }
            return (KeysObject)keyDictionary[key.ToLower()];
        }
        public static KeyLookupTable GetInstance()
        {
            if (instance == null)
            {
                instance = new KeyLookupTable();
            }
            return instance;
        }
    }
    public class ShortcutHandler
    {
        private IDictionary<string, ShortcutCommand> shortcutCommands;
        private static ShortcutHandler instance;
        private ShortcutHandler()
        {
            shortcutCommands = new Dictionary<string, ShortcutCommand>();
        }
        
        public static ShortcutHandler GetInstance()
        {
            if (instance == null)
            {
                instance = new ShortcutHandler();
            }
            return instance;
        }

        public void RegisterShortcut(string shortcutCombineKey, object handler, string handlingMethod)
        {
            shortcutCommands[shortcutCombineKey.ToLower()] = new ShortcutCommand(shortcutCombineKey.ToLower(), handler, handlingMethod);
        }

        public void RemoveShortcut(string combineKey)
        {
            if (shortcutCommands.ContainsKey(combineKey.ToLower()))
            {
                shortcutCommands.Remove(combineKey.ToLower());
            }
        }
        public void HandleEvent(KeyEventArgs ev)
        {
            ICollection<string> keys = shortcutCommands.Keys;
            ShortcutCommand handleCommand = null;
            foreach (string key in keys)
            {
                if (shortcutCommands[key].IsHandlerForEvent(ev))
                {
                    handleCommand = shortcutCommands[key];
                    break;
                }
            }
            if (handleCommand != null)
            {
                handleCommand.Execute();
            }
        }

    }
}
